"use strict"
/*
* 在JavaScript中，用var声明的变量是有作用域的。
* 如果在一个变量的函数体内部，则该变量的作用域为整个函数体内，函数体外不可引用该变量
* */
//变量作用域
function variableScope() {
    function foo1() {
        var x=1;
        x=x+1;
    }
   // x=x+2;//无法在函数体外引用变量

    //如果两个不同的函数各自声明了同一个变量，那么该变量只在各自函数体内起作用，换言之，不同函数内部的同名变量相互独立
    function foo1() {
        var x=1;
        x=x+1;
    }
    function foo3() {
        var x='A';
        x=x+'B';
    }

    //函数嵌套中，内部函数可以访问外部函数声明的变量，外部函数不可访问内部函数声明的变量
    function foo4() {
        var x=1;
        function foo5() {
            var y=x+1;//foo5函数可以访问外部foo4定义的变量x
        }
        var z=y+1;//foo4函数不可访问foo5定义的变量y
    }
    //javascript的函数在查找变量时从自身函数定义开始，从内到外查找，内部函数与外部函数有重名变量，则内部函数的变量将屏蔽外部函数的变量
    function foo6() {
        var x=1;
        function foo7() {
            var x='A';
            console.log('x in foo7()='+x);
        }
        console.log('x in foo6()='+x);
        foo7();
    }
    foo6();
}

//变量提升：javascript的函数定义有个特点，它会先扫描整个函数体的语句，把所有声明的变量“提升”到函数顶部
function hoising() {
    function foo8() {

        var x='hello,'+y;
        console.log(x);//输出hello,undefined(因为JavaScript引擎自动提升了变量y的声明，但不会提升变量y的赋值)
        var y='Bob';
    }
    foo8();
    function foo9() {
        var y='Tom';
        var x='hello,'+y;
        console.log(x);
    }
    foo9();
}

//全局作用域：不在任何函数内定义的变量就具有全局作用域。实际上JavaScript默认有一个全局作用域叫window，
// 全局作用域的变量实际上被绑定到Windows的一个属性
function globalScope() {
    // function foo10() {
    //     var course='learn JavaScript';
    //     alert(course);
    //     window.alert(course);
    // }
    // foo10();
    //
    // function foo11() {
    //     alert('foo');
    //
    // }
    // foo11();
    // window.alert(foo11());

    window.alert('调用windows.alert()');
    //把alert保存到另一个变量
    var old_alert=window.alert;
    window.alert=function () {
        alert('无法用alert()显示了！');
    }
    //恢复alert
    window.alert=old_alert;
    alert('又可以用alert()了！');
}

//名字空间：
/*全局变量会绑定到Windows上，不同JavaScript文件如果使用了相同的全局变量
或者定义了相同名字的顶层函数，都会造成命名冲突，并且很难发现。减少冲突的一个方法是把自己的所有变量和函数全部绑定到一个全局变量中
*/
function names() {
    //唯一的全局变量MYAPP
    var MYAPP={};
    //其他变量
    MYAPP.name='myapp';
    MYAPP.version=1.0;
    //其他函数
    MYAPP.foo=function () {
        return 'foo';
    };

}
//局部作用域
//由于JavaScript的变量作用域实际上是函数内部，我们在for循环等语句块中是无法定义具有局部作用域的变量的
function scope() {
    for(var i=0;i<100;i++){

    }
    i+=100;
}

//为了解决块级作用域，ES6引入了新的关键字let，有let替代var可以申明一个块级作用域的变量
function scope1() {
    var sum=0;
    for (let i=0;i<100;i++){
        sum+=i;
    }
    //i+=1;//语法错误
}

//常量
function constant() {
    //const定义常量，const和let都具有块级作用域
    const PI=3.14;

}

//解构赋值：可以同时对一组变量进行赋值
function destructuringAssignment() {
    var [x,y,z]=['hello','JavaScript','ES6'];
    console.log('x='+x+',y='+y+',z='+z);
    //如果数组本身还有嵌套，也可以通过通过下面的形式进行解构赋值，注意嵌套
    //层次和位置要保持一致
    let [a,[b,c]]=['hi',['how','you']];
    console.log('a='+a+',b='+b+',c='+c);

    //如果需要从一个对象中取出若干属性，也可以使用解构赋值，便于快速获取对象的指定属性
    var Person={
       name:'张小凡',
       age:18,
       gender:'male',
       password:'Z-123456',
       school:'No.4 middle school'
    };
    var {name,age,password}=Person;
    //name,age,password分别被赋值为对应属性
    console.log('name='+name+',age='+age+',password='+password);

    //对一个对象进行解构赋值是，同样可以直接对嵌套的对象属相进行赋值，只要保证对应的层次是一致的
    var Person1={
        name:'陆雪琪',
        age:17,
        gender:'famale',
        address:{
            province:'云南',
            city:'昆明',
            street:'龙泉路'
        }
    }
    var  {name,age,address:{province,city}}=Person1;
    console.log('name='+name+',age='+age+',province='+province+',city='+city);

    var i,j;
    ({i,j}={name:'小张',i:100,j:100});
    console.log('name'+name+',i='+i+',j='+j);
}

//解构赋值使用场景
function Application() {
    //1、不需要中间变量，使用解构赋值可以直接交换两个变量的值
    var x=1,y=2;
    [x,y]=[y,x];
    console.log('x='+x+',y='+y);

    //2、快速获取当前页面的路径和域名
    var {hostname:domain,pathname:path}=location;
    console.log('hostname='+domain+',pathname='+path);

    //3、如果一个函数接收一个对象作为参数，那么，可以使用解构直接把对象的属性绑定到变量中
    function buildDate({year,month,day,hours=0,minute=0,second=0}) {
        return new Date(year+'-'+month+'-'+day+'-'+hours+':'+minute+':'+second);
    }
    console.log(buildDate({year:2018,month:6,day:7}));
    console.log(buildDate({year:2018,month:6,day:7,hours:12,minute:4}));
}